#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned char* base64Encode(const unsigned char *src);
unsigned char* base64Decode(const unsigned char* src);
int is_base64(unsigned char src);

#define NUM "1234"

const unsigned char *base64String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

int main(void)
{
	unsigned char *dst, *dst1;
	unsigned char src[20] = {0};
	unsigned char src2[30] = {0};
	strncpy(src, NUM, strlen(NUM));
	printf("src=%s\n", src);
	dst = base64Encode(src);
	printf("dst=%s\n", dst);

	sprintf(src2, "%s", dst);
	printf("src2=%s\n", src2);	
	dst1 = base64Decode(src2);
	printf("dst=%s\n", dst1);
	return 0;
}


unsigned int findIndex(unsigned char dst)
{
	const unsigned char * tmp =  strchr(base64String, dst);
	return tmp - base64String;
}

int is_base64(unsigned char src)
{
	return (isalnum(src) || src == '+' || src == '/') ? 1 : 0;
}

unsigned char* base64Encode(const unsigned char *src)
{
	int i = 0;
	int k = 0;
	int j = 0;
	int w = 0;
	int len = strlen(src);
	unsigned char str3[3] = {0};
	unsigned char str4[4] = {0};
	unsigned char* dst = (unsigned char *)malloc(sizeof(unsigned char) * len+1); 
	//check the src

	while(j < len)
	{
		str3[i++] = src[j++];

		if(i == 3)
		{
			str4[0] = (str3[0] & 0xfc) >> 2;
			str4[1] = ((str3[0] & 0x03) << 4) + ((str3[1] & 0xf0) >> 4);
			str4[2] = ((str3[1] & 0x0f) << 2) + ((str3[2] & 0xc0) >> 6);
 			str4[3] = (str3[2] & 0x3f);

 			for(k = 0; k < 4; k++)
				dst[w++] = base64String[str4[k]];
 			i = 0;
		}

	}

	if(i != 0)
	{
		for(k = i; k < 3; k++)
		{
			str3[k] = '\0';
		}

		str4[0] = (str3[0] & 0xfc) >> 2;
		str4[1] = (str3[0] & 0x03) << 4 + (str3[1] & 0xf0) >> 4;
		str4[2] = (str3[1] & 0x0f) << 2 + (str3[2] & 0xc0) >> 6;
			str4[3] = str3[2] & 0x3f;		
	
			for(k = 0; k < i+1; k++)
			dst[w++] = base64String[str4[k]];

		for(k = i; k < 3; k++)
		{
			dst[w++] = '=';
		}
	}
		
	dst[w] = '\0';
	return dst;
}

unsigned char* base64Decode(const unsigned char* src)
{
	int i = 0;
	int k = 0;
	int j = 0;
	int w = 0;
	int len = strlen(src);
	unsigned char str3[3] = {0};
	unsigned char str4[4] = {0};
	unsigned char* dst = (unsigned char *)malloc(sizeof(unsigned char) * len + 1);

	while(j < len && src[j] != '=' && is_base64(src[j]))
	{
		str4[i++] = src[j++];

		if(i == 4)
		{
			for(k=0; k < 4; k++)
			{
				str4[k] = (unsigned char)findIndex(str4[k]);
			}

			str3[0] = (str4[0] << 2) + ((str4[1] & 0x30) >> 4);
			str3[1] = ((str4[1] & 0x0f) << 4) + ((str4[2] & 0x3c) >> 2);
			str3[2] = ((str4[2] & 0x03) << 6) + str4[3];

			for(k=0; k < 3; k++)
			{
				dst[w++] = str3[k];

			}

			i = 0;
		}
	}

	if(i!=0)
	{
		for(k=i; k<4; k++)
		{
			str4[k] = 0;
		}

		for(k=0; k < 4; k++)
		{
			str4[k] = (unsigned char)findIndex(str4[k]);
		}

		str3[0] = (str4[0] << 2) + ((str4[1] & 0x30) >> 4);
		str3[1] = ((str4[1] & 0x0f) << 4) + ((str4[2] & 0x3c) >> 2);
		str3[2] = ((str4[2] & 0x03) << 6) + str4[3];

		for (k = 0; k < i - 1; k++) 
			dst[w++] = str3[k];
	}

	dst[w] = '\0';
	return dst;
}